package com.xneure.database;

import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.apache.ibatis.binding.MapperRegistry;
import org.apache.ibatis.builder.CacheRefResolver;
import org.apache.ibatis.builder.ResultMapResolver;
import org.apache.ibatis.builder.annotation.MethodResolver;
import org.apache.ibatis.builder.xml.XMLStatementBuilder;
import org.apache.ibatis.cache.Cache;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.keygen.KeyGenerator;
import org.apache.ibatis.executor.loader.ProxyFactory;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.io.VFS;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMap;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.parsing.XNode;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.ReflectorFactory;
import org.apache.ibatis.reflection.factory.ObjectFactory;
import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
import org.apache.ibatis.scripting.LanguageDriver;
import org.apache.ibatis.scripting.LanguageDriverRegistry;
import org.apache.ibatis.session.AutoMappingBehavior;
import org.apache.ibatis.session.AutoMappingUnknownColumnBehavior;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.LocalCacheScope;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.transaction.Transaction;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeAliasRegistry;
import org.apache.ibatis.type.TypeHandlerRegistry;

public class ExtConfiguration extends Configuration{
	private Map<Integer,Configuration> agentConf = new HashMap<Integer,Configuration>(){
		private static final long serialVersionUID = 4861161176136996414L;

		@Override
		public Configuration get(Object key){
			Configuration configuration = super.get(key);
			if(null == configuration){
				try{
					configuration = sqlSessionFactory.buildSqlSessionFactory(sqlSessionFactory.scanMapper());
					super.put(sqlSessionFactory.getDataSource().hashCode(),configuration);
				}catch(IOException e){
					e.printStackTrace();
				}
			}
			return configuration;
		}
	};
	private MyBatisSqlSessionFactory sqlSessionFactory;

	public ExtConfiguration(MyBatisSqlSessionFactory myBatisSqlSessionFactory){
		this.sqlSessionFactory = myBatisSqlSessionFactory;
	}

	public Configuration getConfiguration(){
		return agentConf.get(sqlSessionFactory.getDataSource().hashCode());
	}

	@Override
	public String getLogPrefix(){
		return getConfiguration().getLogPrefix();
	}

	@Override
	public void setLogPrefix(String logPrefix){
		getConfiguration().setLogPrefix(logPrefix);
	}

	@Override
	public Class<? extends Log> getLogImpl(){
		return getConfiguration().getLogImpl();
	}

	@Override
	public Class<? extends VFS> getVfsImpl(){
		return getConfiguration().getVfsImpl();
	}

	@Override
	public boolean isCallSettersOnNulls(){
		return getConfiguration().isCallSettersOnNulls();
	}

	@Override
	public void setCallSettersOnNulls(boolean callSettersOnNulls){
		getConfiguration().setCallSettersOnNulls(callSettersOnNulls);
	}

	@Override
	public String getDatabaseId(){
		return getConfiguration().getDatabaseId();
	}

	@Override
	public void setDatabaseId(String databaseId){
		getConfiguration().setDatabaseId(databaseId);
	}

	@Override
	public Class<?> getConfigurationFactory(){
		return getConfiguration().getConfigurationFactory();
	}

	@Override
	public void setConfigurationFactory(Class<?> configurationFactory){
		getConfiguration().setConfigurationFactory(configurationFactory);
	}

	@Override
	public boolean isSafeResultHandlerEnabled(){
		return getConfiguration().isSafeResultHandlerEnabled();
	}

	@Override
	public void setSafeResultHandlerEnabled(boolean safeResultHandlerEnabled){
		getConfiguration().setSafeResultHandlerEnabled(safeResultHandlerEnabled);
	}

	@Override
	public boolean isSafeRowBoundsEnabled(){
		return getConfiguration().isSafeRowBoundsEnabled();
	}

	@Override
	public void setSafeRowBoundsEnabled(boolean safeRowBoundsEnabled){
		getConfiguration().setSafeRowBoundsEnabled(safeRowBoundsEnabled);
	}

	@Override
	public boolean isMapUnderscoreToCamelCase(){
		return getConfiguration().isMapUnderscoreToCamelCase();
	}

	@Override
	public void setMapUnderscoreToCamelCase(boolean mapUnderscoreToCamelCase){
		getConfiguration().setMapUnderscoreToCamelCase(mapUnderscoreToCamelCase);
	}

	@Override
	public void addLoadedResource(String resource){
		getConfiguration().addLoadedResource(resource);
	}

	@Override
	public boolean isResourceLoaded(String resource){
		return getConfiguration().isResourceLoaded(resource);
	}

	@Override
	public Environment getEnvironment(){
		return getConfiguration().getEnvironment();
	}

	@Override
	public void setEnvironment(Environment environment){
		getConfiguration().setEnvironment(environment);
	}

	@Override
	public AutoMappingBehavior getAutoMappingBehavior(){
		return getConfiguration().getAutoMappingBehavior();
	}

	@Override
	public void setAutoMappingBehavior(AutoMappingBehavior autoMappingBehavior){
		getConfiguration().setAutoMappingBehavior(autoMappingBehavior);
	}

	@Override
	public AutoMappingUnknownColumnBehavior getAutoMappingUnknownColumnBehavior(){
		return getConfiguration().getAutoMappingUnknownColumnBehavior();
	}

	@Override
	public void setAutoMappingUnknownColumnBehavior(AutoMappingUnknownColumnBehavior autoMappingUnknownColumnBehavior){
		getConfiguration().setAutoMappingUnknownColumnBehavior(autoMappingUnknownColumnBehavior);
	}

	@Override
	public boolean isLazyLoadingEnabled(){
		return getConfiguration().isLazyLoadingEnabled();
	}

	@Override
	public void setLazyLoadingEnabled(boolean lazyLoadingEnabled){
		getConfiguration().setLazyLoadingEnabled(lazyLoadingEnabled);
	}

	@Override
	public ProxyFactory getProxyFactory(){
		return getConfiguration().getProxyFactory();
	}

	@Override
	public void setProxyFactory(ProxyFactory proxyFactory){
		getConfiguration().setProxyFactory(proxyFactory);
	}

	@Override
	public boolean isAggressiveLazyLoading(){
		return getConfiguration().isAggressiveLazyLoading();
	}

	@Override
	public void setAggressiveLazyLoading(boolean aggressiveLazyLoading){
		getConfiguration().setAggressiveLazyLoading(aggressiveLazyLoading);
	}

	@Override
	public boolean isMultipleResultSetsEnabled(){
		return getConfiguration().isMultipleResultSetsEnabled();
	}

	@Override
	public void setMultipleResultSetsEnabled(boolean multipleResultSetsEnabled){
		getConfiguration().setMultipleResultSetsEnabled(multipleResultSetsEnabled);
	}

	@Override
	public Set<String> getLazyLoadTriggerMethods(){
		return getConfiguration().getLazyLoadTriggerMethods();
	}

	@Override
	public void setLazyLoadTriggerMethods(Set<String> lazyLoadTriggerMethods){
		getConfiguration().setLazyLoadTriggerMethods(lazyLoadTriggerMethods);
	}

	@Override
	public boolean isUseGeneratedKeys(){
		return getConfiguration().isUseGeneratedKeys();
	}

	@Override
	public void setUseGeneratedKeys(boolean useGeneratedKeys){
		getConfiguration().setUseGeneratedKeys(useGeneratedKeys);
	}

	@Override
	public ExecutorType getDefaultExecutorType(){
		return getConfiguration().getDefaultExecutorType();
	}

	@Override
	public void setDefaultExecutorType(ExecutorType defaultExecutorType){
		getConfiguration().setDefaultExecutorType(defaultExecutorType);
	}

	@Override
	public boolean isCacheEnabled(){
		return getConfiguration().isCacheEnabled();
	}

	@Override
	public void setCacheEnabled(boolean cacheEnabled){
		getConfiguration().setCacheEnabled(cacheEnabled);
	}

	@Override
	public Integer getDefaultStatementTimeout(){
		return getConfiguration().getDefaultStatementTimeout();
	}

	@Override
	public void setDefaultStatementTimeout(Integer defaultStatementTimeout){
		getConfiguration().setDefaultStatementTimeout(defaultStatementTimeout);
	}

	@Override
	public Integer getDefaultFetchSize(){
		return getConfiguration().getDefaultFetchSize();
	}

	@Override
	public void setDefaultFetchSize(Integer defaultFetchSize){
		getConfiguration().setDefaultFetchSize(defaultFetchSize);
	}

	@Override
	public boolean isUseColumnLabel(){
		return getConfiguration().isUseColumnLabel();
	}

	@Override
	public void setUseColumnLabel(boolean useColumnLabel){
		getConfiguration().setUseColumnLabel(useColumnLabel);
	}

	@Override
	public LocalCacheScope getLocalCacheScope(){
		return getConfiguration().getLocalCacheScope();
	}

	@Override
	public void setLocalCacheScope(LocalCacheScope localCacheScope){
		getConfiguration().setLocalCacheScope(localCacheScope);
	}

	@Override
	public JdbcType getJdbcTypeForNull(){
		return getConfiguration().getJdbcTypeForNull();
	}

	@Override
	public void setJdbcTypeForNull(JdbcType jdbcTypeForNull){
		getConfiguration().setJdbcTypeForNull(jdbcTypeForNull);
	}

	@Override
	public Properties getVariables(){
		return getConfiguration().getVariables();
	}

	@Override
	public void setVariables(Properties variables){
		getConfiguration().setVariables(variables);
	}

	@Override
	public TypeHandlerRegistry getTypeHandlerRegistry(){
		return getConfiguration().getTypeHandlerRegistry();
	}

	@Override
	public TypeAliasRegistry getTypeAliasRegistry(){
		return getConfiguration().getTypeAliasRegistry();
	}

	@Override
	public MapperRegistry getMapperRegistry(){
		return getConfiguration().getMapperRegistry();
	}

	@Override
	public ReflectorFactory getReflectorFactory(){
		return getConfiguration().getReflectorFactory();
	}

	@Override
	public void setReflectorFactory(ReflectorFactory reflectorFactory){
		getConfiguration().setReflectorFactory(reflectorFactory);
	}

	@Override
	public ObjectFactory getObjectFactory(){
		return getConfiguration().getObjectFactory();
	}

	@Override
	public void setObjectFactory(ObjectFactory objectFactory){
		getConfiguration().setObjectFactory(objectFactory);
	}

	@Override
	public ObjectWrapperFactory getObjectWrapperFactory(){
		return getConfiguration().getObjectWrapperFactory();
	}

	@Override
	public void setObjectWrapperFactory(ObjectWrapperFactory objectWrapperFactory){
		getConfiguration().setObjectWrapperFactory(objectWrapperFactory);
	}

	@Override
	public List<Interceptor> getInterceptors(){
		return getConfiguration().getInterceptors();
	}

	@Override
	public LanguageDriverRegistry getLanguageRegistry(){
		return getConfiguration().getLanguageRegistry();
	}

	@Override
	public void setDefaultScriptingLanguage(Class<?> driver){
		getConfiguration().setDefaultScriptingLanguage(driver);
	}

	@Override
	public LanguageDriver getDefaultScriptingLanguageInstance(){
		return getConfiguration().getDefaultScriptingLanguageInstance();
	}

	@Override
	public MetaObject newMetaObject(Object object){
		return getConfiguration().newMetaObject(object);
	}

	@Override
	public ParameterHandler newParameterHandler(MappedStatement mappedStatement,Object parameterObject,BoundSql boundSql){
		return getConfiguration().newParameterHandler(mappedStatement,parameterObject,boundSql);
	}

	@SuppressWarnings("rawtypes")
	@Override
	public ResultSetHandler newResultSetHandler(Executor executor,MappedStatement mappedStatement,RowBounds rowBounds,ParameterHandler parameterHandler,
			ResultHandler resultHandler,BoundSql boundSql)
	{
		return getConfiguration().newResultSetHandler(executor,mappedStatement,rowBounds,parameterHandler,resultHandler,boundSql);
	}

	@SuppressWarnings("rawtypes")
	@Override
	public StatementHandler newStatementHandler(Executor executor,MappedStatement mappedStatement,Object parameterObject,RowBounds rowBounds,
			ResultHandler resultHandler,BoundSql boundSql)
	{
		return getConfiguration().newStatementHandler(executor,mappedStatement,parameterObject,rowBounds,resultHandler,boundSql);
	}

	@Override
	public Executor newExecutor(Transaction transaction){
		return getConfiguration().newExecutor(transaction);
	}

	@Override
	public Executor newExecutor(Transaction transaction,ExecutorType executorType){
		return getConfiguration().newExecutor(transaction,executorType);
	}

	@Override
	public void addKeyGenerator(String id,KeyGenerator keyGenerator){
		getConfiguration().addKeyGenerator(id,keyGenerator);
	}

	@Override
	public Collection<String> getKeyGeneratorNames(){
		return getConfiguration().getKeyGeneratorNames();
	}

	@Override
	public Collection<KeyGenerator> getKeyGenerators(){
		return getConfiguration().getKeyGenerators();
	}

	@Override
	public KeyGenerator getKeyGenerator(String id){
		return getConfiguration().getKeyGenerator(id);
	}

	@Override
	public boolean hasKeyGenerator(String id){
		return getConfiguration().hasKeyGenerator(id);
	}

	@Override
	public void addCache(Cache cache){
		getConfiguration().addCache(cache);
	}

	@Override
	public Collection<String> getCacheNames(){
		return getConfiguration().getCacheNames();
	}

	@Override
	public Collection<Cache> getCaches(){
		return getConfiguration().getCaches();
	}

	@Override
	public Cache getCache(String id){
		return getConfiguration().getCache(id);
	}

	@Override
	public boolean hasCache(String id){
		return getConfiguration().hasCache(id);
	}

	@Override
	public void addResultMap(ResultMap rm){
		getConfiguration().addResultMap(rm);
	}

	@Override
	public Collection<String> getResultMapNames(){
		return getConfiguration().getResultMapNames();
	}

	@Override
	public Collection<ResultMap> getResultMaps(){
		return getConfiguration().getResultMaps();
	}

	@Override
	public ResultMap getResultMap(String id){
		return getConfiguration().getResultMap(id);
	}

	@Override
	public boolean hasResultMap(String id){
		return getConfiguration().hasResultMap(id);
	}

	@Override
	public void addParameterMap(ParameterMap pm){
		getConfiguration().addParameterMap(pm);
	}

	@Override
	public Collection<String> getParameterMapNames(){
		return getConfiguration().getParameterMapNames();
	}

	@Override
	public Collection<ParameterMap> getParameterMaps(){
		return getConfiguration().getParameterMaps();
	}

	@Override
	public ParameterMap getParameterMap(String id){
		return getConfiguration().getParameterMap(id);
	}

	@Override
	public boolean hasParameterMap(String id){
		return getConfiguration().hasParameterMap(id);
	}

	@Override
	public void addMappedStatement(MappedStatement ms){
		getConfiguration().addMappedStatement(ms);
	}

	@Override
	public Collection<String> getMappedStatementNames(){
		return getConfiguration().getMappedStatementNames();
	}

	@Override
	public Collection<MappedStatement> getMappedStatements(){
		return getConfiguration().getMappedStatements();
	}

	@Override
	public Collection<XMLStatementBuilder> getIncompleteStatements(){
		return getConfiguration().getIncompleteStatements();
	}

	@Override
	public void addIncompleteStatement(XMLStatementBuilder incompleteStatement){
		getConfiguration().addIncompleteStatement(incompleteStatement);
	}

	@Override
	public Collection<CacheRefResolver> getIncompleteCacheRefs(){
		return getConfiguration().getIncompleteCacheRefs();
	}

	@Override
	public void addIncompleteCacheRef(CacheRefResolver incompleteCacheRef){
		getConfiguration().addIncompleteCacheRef(incompleteCacheRef);
	}

	@Override
	public Collection<ResultMapResolver> getIncompleteResultMaps(){
		return getConfiguration().getIncompleteResultMaps();
	}

	@Override
	public void addIncompleteResultMap(ResultMapResolver resultMapResolver){
		getConfiguration().addIncompleteResultMap(resultMapResolver);
	}

	@Override
	public void addIncompleteMethod(MethodResolver builder){
		getConfiguration().addIncompleteMethod(builder);
	}

	@Override
	public Collection<MethodResolver> getIncompleteMethods(){
		return getConfiguration().getIncompleteMethods();
	}

	@Override
	public MappedStatement getMappedStatement(String id){
		return getConfiguration().getMappedStatement(id);
	}

	@Override
	public MappedStatement getMappedStatement(String id,boolean validateIncompleteStatements){
		return getConfiguration().getMappedStatement(id,validateIncompleteStatements);
	}

	@Override
	public Map<String,XNode> getSqlFragments(){
		return getConfiguration().getSqlFragments();
	}

	@Override
	public void addInterceptor(Interceptor interceptor){
		getConfiguration().addInterceptor(interceptor);
	}

	@Override
	public void addMappers(String packageName,Class<?> superType){
		getConfiguration().addMappers(packageName,superType);
	}

	@Override
	public void addMappers(String packageName){
		getConfiguration().addMappers(packageName);
	}

	@Override
	public <T> void addMapper(Class<T> type){
		getConfiguration().addMapper(type);
	}

	@Override
	public <T> T getMapper(Class<T> type,SqlSession sqlSession){
		return getConfiguration().getMapper(type,sqlSession);
	}

	@Override
	public boolean hasMapper(Class<?> type){
		return getConfiguration().hasMapper(type);
	}

	@Override
	public boolean hasStatement(String statementName){
		return getConfiguration().hasStatement(statementName);
	}

	@Override
	public boolean hasStatement(String statementName,boolean validateIncompleteStatements){
		return getConfiguration().hasStatement(statementName,validateIncompleteStatements);
	}

	@Override
	public void addCacheRef(String namespace,String referencedNamespace){
		getConfiguration().addCacheRef(namespace,referencedNamespace);
	}
}
